package study.intconsulting.util;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;

public class JaxbUtil {

	public static String convertToXml(Object source, Class... type) {
		String result;
		StringWriter sw = new StringWriter();
		sw.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");

		try {
			JAXBContext context = JAXBContext.newInstance(type);
			Marshaller marshaller = context.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

			marshaller.marshal(source, sw);

			result = sw.toString();
		} catch (JAXBException e) {
			throw new RuntimeException(e);
		}

		return result;
	}

	public static Object convertToPojo(String xml, Class... type) {
		Object obj;
		StringReader sr = new StringReader(xml);
		try {
			JAXBContext context = JAXBContext.newInstance(type);
			Unmarshaller unmarshaller = context.createUnmarshaller();
			// unmarshaller.setValidating(true);

			obj = unmarshaller.unmarshal(sr);
		} catch (JAXBException e) {
			throw new RuntimeException(e);
		}
		return obj;
	}

//	public static String pojoToJson(Employee employee) throws JAXBException, JsonParseException, JsonMappingException, IOException {
//		ObjectMapper mapper = new ObjectMapper();
//		AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
//		mapper.getSerializationConfig().setAnnotationIntrospector(introspector);
//		String jsonData = mapper.writeValueAsString(employee);
//		return jsonData;
//	}

//	public static Employee jsonToPojo(String jsonData) throws JAXBException, JsonParseException, JsonMappingException, IOException {
//		ObjectMapper mapper = new ObjectMapper();
//		AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
//		mapper.getDeserializationConfig().setAnnotationIntrospector(
//				introspector);
//		Employee employee = mapper.readValue(jsonData, Employee.class);
//		return employee;
//	}

//	public void pojoToXSD(JAXBContext context, OutputStream out)
//	// public void pojoToXSD(JAXBContext context, Object pojo, OutputStream out)
//			throws IOException, TransformerException {
//		final List<DOMResult> results = new ArrayList<DOMResult>();
//		context.generateSchema(new SchemaOutputResolver() {
//			@Override
//			public Result createOutput(String ns, String file)
//					throws IOException {
//				DOMResult result = new DOMResult();
//				result.setSystemId(file);
//				results.add(result);
//				return result;
//			}
//		});
//
//		DOMResult domResult = results.get(0);
//		Document doc = (Document) domResult.getNode();
//
//		// Use a Transformer for output
//		TransformerFactory tFactory = TransformerFactory.newInstance();
//		Transformer transformer = tFactory.newTransformer();
//		DOMSource source = new DOMSource(doc);
//		StreamResult result = new StreamResult(out);
//		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//		transformer.transform(source, result);
//	}
	
	public static String extractValue(String xml, String xpathExpression) {
		String actual;
		try {
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
					.newInstance();
			documentBuilderFactory.setNamespaceAware(true);
			documentBuilderFactory.setIgnoringElementContentWhitespace(true);
			DocumentBuilder docBuilder = documentBuilderFactory
					.newDocumentBuilder();

			byte[] bytes = xml.getBytes("UTF-8");
			InputStream inputStream = new ByteArrayInputStream(bytes);
			Document doc = docBuilder.parse(inputStream);
			XPathFactory xPathFactory = XPathFactory.newInstance();
			XPath xpath = xPathFactory.newXPath();

			// XPathExpression ex = xpath.compile(xpathExpression);
			// Object obj = ex.evaluate(doc, XPathConstants.STRING);
			actual = xpath
					.evaluate(xpathExpression, doc, XPathConstants.STRING)
					.toString();

		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		return actual;
	}
}
